/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "stub.h"
#include "gmock/gmock-actions.h"
#include "SnapshotRestore.h"
#include "SnapshotCommon.h"
#include "PluginUtilities.h"

using ::testing::_;
using testing::AllOf;
using ::testing::AnyNumber;
using ::testing::AtLeast;
using testing::ByMove;
using testing::DoAll;
using ::testing::Eq;
using ::testing::Field;
using ::testing::Ge;
using ::testing::Gt;
using testing::InitGoogleMock;
using ::testing::Invoke;
using ::testing::Ne;
using ::testing::Return;
using ::testing::Sequence;
using ::testing::SetArgReferee;
using ::testing::SetArgumentPointee;
using ::testing::Throw;
using namespace std;

class SnapshotRestoreTest : public testing::Test {
public:
    void SetUp();
    void TearDown();
    static void SetUpTestCase();
    static void TearDownTestCase();
    unique_ptr<SnapshotRestore> m_snapshotRestore;
};

static AppProtect::RestoreJob RestoreJobSetup()
{
    AppProtect::RestoreJob restoreJob;
    restoreJob.requestId = "123456789";
    restoreJob.jobId = "111111";
    restoreJob.targetEnv.id = "123";
    restoreJob.targetEnv.name = "123";
    restoreJob.targetEnv.port = 8088;
    restoreJob.targetEnv.auth.authkey = "admin";
    restoreJob.targetEnv.auth.authPwd = "Huawei@123456789";
    restoreJob.targetEnv.subType = "1";
    restoreJob.targetObject.id = "123";
    restoreJob.targetObject.name = "123";
    restoreJob.targetObject.parentId =" 4564654645564";
    restoreJob.targetObject.parentName = "test_filesystem";
    restoreJob.targetObject.subType ="5";
    restoreJob.targetEnv.endpoint = "127.0.0.1";
    restoreJob.targetObject.auth.authkey = "admin";
    restoreJob.targetObject.auth.authPwd = "Huawei@123456789";
    restoreJob.targetObject.extendInfo = "{\"authMode\":\"1\",\"filters\":\"\",\"ip\":\"10.28.12.144\""
                                         ",\"kerberosId\":\"0\",\"shareMode\":\"1\"}";
    Copy copy;
    copy.name = "pppp";
    restoreJob.copies.push_back(copy);
    return restoreJob;
}

static SubJob CreateSubJob()
{
    SubJob subJob;
    subJob.jobId = "jobId123";
    subJob.subJobId = "subJob123";
    subJob.jobName = "XYZ";
    subJob.jobPriority = 1;
    subJob.jobInfo = "{\"ControlFile\":\"\",\"SubTaskType\":1,\"Ext\":\"\"}";
    return subJob;
}

static void Void_Stub(void* obj) {
    return;
}

static std::string GetDeployType_stub_secure_machine()
{
    cout << "Enter GetDeployType_stub_secure_machine" << endl;
    return "d5";
}

static std::string GetDeployType_stub_anti_ransomware()
{
    cout << "Enter GetDeployType_stub_anti_ransomware" << endl;
    return "d4";
}

void SnapshotRestoreTest::SetUp()
{   
    Stub stub;
    stub.set(sleep, Void_Stub);
    m_snapshotRestore = std::make_unique<SnapshotRestore>();
    m_snapshotRestore->m_jobCommonInfo =
            std::make_shared<JobCommonInfo>(std::make_shared<RestoreJob>(RestoreJobSetup()));
}

void SnapshotRestoreTest::TearDown()
{
    Stub stub;
    stub.reset(sleep);
}

void SnapshotRestoreTest::SetUpTestCase() {}

void SnapshotRestoreTest::TearDownTestCase() {}

static int ReportJobDetails_Stub(void *obj) {
    return Module::SUCCESS;
}

static int PrerequisiteJobInner_Stub_Fail(void* obj)
{
    return Module::FAILED;
}

static void AddNewJob_Stub(void* obj) {
    return;
}

static int CheckNetwork_Stub(void* obj) {
    return Module::SUCCESS;
}

static int GetContainerDoradoIp_Stub(void* obj) {
    return Module::SUCCESS;
}

static int QuerySnapshot_Stub(void *obj, string snapshotName, string SnapshotId) {
    SnapshotId = "11111111";
    return Module::SUCCESS;
}

static int QuerySnapshotSuccess_Stub(void *obj, string snapshotName, string SnapshotId) {
    SnapshotId = "";
    return Module::SUCCESS;
}

static int QuerySnapshotFail_Stub(void *obj, string snapshotName, string SnapshotId) {
    SnapshotId = "222222";
    return Module::FAILED;
}

static int CreateSnapshotWithSnapTag_Stub(void* obj) {
    return Module::SUCCESS;
}

static int InitJobInfo_stub(void* obj) {
    return Module::SUCCESS;
}

static int PostJobInner_stub() {
    return Module::FAILED;
}

static int QuerySnapshotRollBackStatus_Stub(void* obj,string fileSystemName,string& snapshotId,
                                            string& rollbackRate, string& rollbackStatus, string& endTime) {
    rollbackStatus = "0";
    rollbackRate = "100";
    endTime = "9999999999";
    return Module::SUCCESS;
}

static int QuerySnapshotRollBackStatusFail_Stub(void* obj,string fileSystemName,string& snapshotId,
                                            string& rollbackRate, string& rollbackStatus, string& endTime) {
    return Module::FAILED;
}

static int RollBackBySnapShotIdWithVstoreId_Stub(void* obj) {
    return Module::SUCCESS;
}

static int InitDeviceInfo_Stub(void* obj) {
    return Module::FAILED;
}

/**
 * 用例名称：PrerequisiteJob_Success
 * 前置条件：无
 * check点：前置任务成功
 */
TEST_F(SnapshotRestoreTest, PrerequisiteJob_Success)
{
    Stub stub;
    stub.set((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);

    int ret = m_snapshotRestore->PrerequisiteJob();
    EXPECT_EQ(ret, Module::SUCCESS);

    stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
}

/**
 * 用例名称：PrerequisiteJob_Fail
 * 前置条件：无
 * check点：前置任务失败
 */
TEST_F(SnapshotRestoreTest, PrerequisiteJob_Fail)
{
    Stub stub;
    stub.set((void(SnapshotRestore::*)(const std::string& label,
        const JobLogLevel::type &level, const SubJobStatus::type sts, int progress))
        ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
    stub.set(ADDR(SnapshotRestore, PrerequisiteJobInner), PrerequisiteJobInner_Stub_Fail);

    EXPECT_EQ(m_snapshotRestore->PrerequisiteJob(), Module::FAILED);

    stub.reset(ADDR(SnapshotRestore, PrerequisiteJobInner));
    stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
}

/**
 * 用例名称：GenerateSubJob_Success
 * 前置条件：无
 * check点：生成任务成功
 */
TEST_F(SnapshotRestoreTest, GenerateSubJob_Success)
{
    Stub stub;
    stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
    stub.set(ADDR(JobService, AddNewJob), AddNewJob_Stub);
    stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

    int ret = m_snapshotRestore->GenerateSubJob();
    EXPECT_EQ(ret, Module::SUCCESS);

    stub.reset(ADDR(JobService, AddNewJob));
    stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
    stub.reset(PluginUtils::GetDeployType);
}

/**
 * 用例名称：GenerateSubJob_Success
 * 前置条件：无
 * check点：生成任务成功
 */
TEST_F(SnapshotRestoreTest, GenerateSubJob_Fail)
{
    Stub stub;
    stub.set((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
    stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

    int ret = m_snapshotRestore->GenerateSubJob();
    EXPECT_EQ(ret, Module::FAILED);

    stub.reset((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
        stub.reset(PluginUtils::GetDeployType);
}

/**
 * 用例名称：ExecuteSubJob_Success
 * 前置条件：无
 * check点：执行任务成功
 */
// TEST_F(SnapshotRestoreTest, ExecuteSubJob_Success)
// {
//     std::shared_ptr<SubJob> subJob = std::make_shared<SubJob>(CreateSubJob());
//     m_snapshotRestore->SetSubJob(subJob);
//     Stub stub;
//     stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
//     stub.set(ADDR(SnapshotCommon, CheckNetwork), CheckNetwork_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshot), QuerySnapshot_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2), QuerySnapshotRollBackStatus_Stub);
//     stub.set(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId), RollBackBySnapShotIdWithVstoreId_Stub);
//     stub.set(sleep, AddNewJob_Stub);
//     stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

//     int ret = m_snapshotRestore->ExecuteSubJob();
//     EXPECT_EQ(ret, Module::SUCCESS);

//     stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
//     stub.reset(ADDR(SnapshotCommon, CheckNetwork));
//     stub.reset(ADDR(Module::DoradoNas, CreateSnapshotWithSnapTag));
//     stub.reset(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2));
//     stub.reset(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId));
//     stub.reset(sleep);
//     stub.reset(PluginUtils::GetDeployType);
// }

/**
 * 用例名称：ExecuteSubJob_InitJobInfoFailed
 * 前置条件：无
 * check点：执行任务失败，初始化job信息失败
 */
// TEST_F(SnapshotRestoreTest, ExecuteSubJob_InitJobInfoFailed)
// {
//     std::shared_ptr<SubJob> subJob = std::make_shared<SubJob>(CreateSubJob());
//     m_snapshotRestore->SetSubJob(subJob);
//     Stub stub;
//     stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
//     stub.set(ADDR(SnapshotCommon, CheckNetwork), CheckNetwork_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshot), QuerySnapshot_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2), QuerySnapshotRollBackStatus_Stub);
//     stub.set(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId), RollBackBySnapShotIdWithVstoreId_Stub);
//     stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

//     // 改变预制数据,extendInfo为空字符串
//     std::shared_ptr<RestoreJob> jobInfoStr =
//             dynamic_pointer_cast<RestoreJob>(m_snapshotRestore->m_jobCommonInfo->GetJobInfo());
//     jobInfoStr->targetObject.extendInfo = "";

//     EXPECT_EQ(m_snapshotRestore->ExecuteSubJob(), Module::FAILED);

//     stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
//     stub.reset(ADDR(SnapshotCommon, CheckNetwork));
//     stub.reset(ADDR(Module::DoradoNas, CreateSnapshotWithSnapTag));
//     stub.reset(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2));
//     stub.reset(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId));
//     stub.reset(PluginUtils::GetDeployType);
// }

/**
 * 用例名称：ExecuteSubJob_InitDeviceInfoFailed
 * 前置条件：无
 * check点：执行任务失败，初始化设备信息失败
 */
// TEST_F(SnapshotRestoreTest, ExecuteSubJob_InitDeviceInfoFailed)
// {
//     std::shared_ptr<SubJob> subJob = std::make_shared<SubJob>(CreateSubJob());
//     m_snapshotRestore->SetSubJob(subJob);
//     Stub stub;
//     stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
//     stub.set(ADDR(SnapshotCommon, CheckNetwork), CheckNetwork_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshot), QuerySnapshot_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2), QuerySnapshotRollBackStatus_Stub);
//     stub.set(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId), RollBackBySnapShotIdWithVstoreId_Stub);
//     stub.set(ADDR(SnapshotCommon, InitDeviceInfo), InitDeviceInfo_Stub);
//     stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

//     EXPECT_EQ(m_snapshotRestore->ExecuteSubJob(), Module::FAILED);

//     stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
//     stub.reset(ADDR(SnapshotCommon, CheckNetwork));
//     stub.reset(ADDR(SnapshotCommon, InitDeviceInfo));
//     stub.reset(ADDR(Module::DoradoNas, CreateSnapshotWithSnapTag));
//     stub.reset(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2));
//     stub.reset(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId));
//     stub.reset(PluginUtils::GetDeployType);
// }

/**
 * 用例名称：ExecuteSubJob_InitDeviceInfoFailed
 * 前置条件：无
 * check点：执行任务失败，查询快照回滚状态失败
 */
// TEST_F(SnapshotRestoreTest, ExecuteSubJob_QueryStatusFailed)
// {
//     std::shared_ptr<SubJob> subJob = std::make_shared<SubJob>(CreateSubJob());
//     m_snapshotRestore->SetSubJob(subJob);
//     Stub stub;
//     stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
//     stub.set(ADDR(SnapshotCommon, CheckNetwork), CheckNetwork_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshot), QuerySnapshot_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2), QuerySnapshotRollBackStatusFail_Stub);
//     stub.set(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId), RollBackBySnapShotIdWithVstoreId_Stub);
//     stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

//     EXPECT_EQ(m_snapshotRestore->ExecuteSubJob(), Module::FAILED);

//     stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
//     stub.reset(ADDR(SnapshotCommon, CheckNetwork));
//     stub.reset(ADDR(Module::DoradoNas, CreateSnapshotWithSnapTag));
//     stub.reset(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2));
//     stub.reset(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId));
//     stub.reset(PluginUtils::GetDeployType);
// }

/**
 * 用例名称：ExecuteSubJob_SnapshotNotExist
 * 前置条件：无
 * check点：执行任务失败，快照不存在
 */
// TEST_F(SnapshotRestoreTest, ExecuteSubJob_SnapshotNotExist)
// {
//     std::shared_ptr<SubJob> subJob = std::make_shared<SubJob>(CreateSubJob());
//     m_snapshotRestore->SetSubJob(subJob);
//     Stub stub;
//     stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
//     stub.set(ADDR(SnapshotCommon, CheckNetwork), CheckNetwork_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshot), QuerySnapshotFail_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2), QuerySnapshotRollBackStatus_Stub);
//     stub.set(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId), RollBackBySnapShotIdWithVstoreId_Stub);
//     stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

//     EXPECT_EQ(m_snapshotRestore->ExecuteSubJob(), Module::FAILED);

//     stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
//     stub.reset(ADDR(SnapshotCommon, CheckNetwork));
//     stub.reset(ADDR(Module::DoradoNas, CreateSnapshotWithSnapTag));
//     stub.reset(ADDR(Module::DoradoNas, QuerySnapshotRollBackStatusV2));
//     stub.reset(ADDR(Module::DoradoNas, RollBackBySnapShotIdWithVstoreId));
//     stub.reset(PluginUtils::GetDeployType);
// }

/**
 * 用例名称：PostSubJob_Success
 * 前置条件：无
 * check点：post任务成功
 */
TEST_F(SnapshotRestoreTest, PostSubJob_Success)
{
    std::shared_ptr<SubJob> subJob = std::make_shared<SubJob>(CreateSubJob());
    m_snapshotRestore->SetSubJob(subJob);
    Stub stub;
    stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
    stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

    int ret = m_snapshotRestore->PostJob();
    EXPECT_EQ(ret, Module::SUCCESS);

    stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
        const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
    stub.reset(PluginUtils::GetDeployType);
}

/**
 * 用例名称：PostSubJob_Failed
 * 前置条件：无
 * check点：post任务失败
 */
TEST_F(SnapshotRestoreTest, PostSubJob_Failed)
{
    std::shared_ptr<SubJob> subJob = std::make_shared<SubJob>(CreateSubJob());
    m_snapshotRestore->SetSubJob(subJob);
    Stub stub;
    stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
    stub.set(ADDR(SnapshotRestore, PostJobInner), PostJobInner_stub);
    stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

    int ret = m_snapshotRestore->PostJob();
    EXPECT_EQ(ret, Module::FAILED);

    stub.reset(ADDR(SnapshotRestore, PostJobInner));
    stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
            const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
    stub.reset(PluginUtils::GetDeployType);
}

/**
 * 用例名称：CheckExistSnapshot
 * 前置条件：无
 * check点：QuerySnapshot结果 m_snapshotId为空字符串
 */
// TEST_F(SnapshotRestoreTest, CheckExistSnapshot)
// {
//     std::shared_ptr<SubJob> subJob = std::make_shared<SubJob>(CreateSubJob());
//     m_snapshotRestore->SetSubJob(subJob);
//     Stub stub;
//     stub.set((void(SnapshotRestore::*)(const std::string& label, const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails), ReportJobDetails_Stub);
//     stub.set(ADDR(Module::DoradoNas, QuerySnapshot), QuerySnapshotSuccess_Stub);
//     stub.set(PluginUtils::GetDeployType, GetDeployType_stub_anti_ransomware);

//     int ret = m_snapshotRestore->CheckExistSnapshot();
//     EXPECT_EQ(ret, Module::FAILED);

//     stub.reset(ADDR(Module::DoradoNas, QuerySnapshot));
//     stub.reset((void(SnapshotRestore::*)(const std::string& label,const JobLogLevel::type &level,
//             const SubJobStatus::type sts, int progress))ADDR(SnapshotRestore, ReportJobDetails));
//     stub.reset(PluginUtils::GetDeployType);
// }